package delaunay;

/*
 * Copyright (c) 2005, 2007 by L. Paul Chew.
 * 
 * Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;

import megamu.mesh.Corner;
import megamu.mesh.Region;
import megamu.mesh.Site;

import com.jellyfishumbrella.GL.Vector3d;
import com.jellyfishumbrella.util.Trace;

/**
 * The Delauany applet.
 * 
 * Creates and displays a Delaunay Triangulation (DT) or a Voronoi Diagram (VoD). Has a main program so it is an application as well as an applet.
 * 
 * @author Paul Chew
 * 
 *         Created July 2005. Derived from an earlier, messier version.
 * 
 *         Modified December 2007. Updated some of the Triangulation methods. Added the "Colorful" checkbox. Reorganized the interface between DelaunayAp and DelaunayPanel. Added code to find a Voronoi cell.
 * 
 */
@SuppressWarnings("serial")
public class Delaunay2 {
	private boolean			debug		= false;		// Used for debugging

	private Triangulation	dt;						// Delaunay triangulation
	private Triangle		initialTriangle;			// Initial triangle
	private static int		initialSize	= 10000;		// Size of initial triangle
	private Random			random		= new Random();       // Source of random numbers
	Random R = new Random();

	/**
	 * Create and initialize the DT.
	 */
	public Delaunay2() {
		initialTriangle = new Triangle(new Pnt(-initialSize, -initialSize), new Pnt(initialSize, -initialSize), new Pnt(0, initialSize));
		dt = new Triangulation(initialTriangle);
	}

	/**
	 * If mouse has been pressed inside the delaunayPanel then add a new site.
	 */
	//public void addSite(Vector3d loc) {
	//	Pnt point = new Pnt(loc.x, 0.0, loc.z);
	//	addSite(point);
	//}

	/*
	 * Add a new site to the DT.
	 * 
	 * @param point the site to add
	 */
	//public void addSite(Pnt point) {
	//	dt.delaunayPlace(point);
	//}

	public void addSite(Site currSite) {
		Pnt point = new Pnt(currSite.x(), currSite.z());
		point.iIndex = currSite.iIndex;
		point.jIndex = currSite.jIndex;

		dt.delaunayPlace(point);
	}

	/**
	 * Re-initialize the DT.
	 */
	public void clear() {
		dt = new Triangulation(initialTriangle);
	}

	/**
	 * Draw all the Voronoi cells.
	 * 
	 * @param withFill
	 *            true iff drawing Voronoi cells with fill colors
	 * @param withSites
	 *            true iff drawing the site for each Voronoi cell
	 */
	public ArrayList<Region> getRegions(Site[][] sites) {
		// Keep track of sites done; no drawing for initial triangles sites
		ArrayList<Region> regions = new ArrayList<Region>();

		for (Triangle triangle : dt) {
			Site[] site = new Site[3];
			int i = 0;
			for (Pnt point : triangle) {
				if(point.iIndex != -1 && point.jIndex!= -1){
					site[i++] = sites[point.iIndex][point.jIndex];
				}
			}
			
			if(site[0] != null){
				if(site[1] != null){
					site[0].addNeighbor(site[1]);
					if(site[2] != null){
						site[0].addNeighbor(site[2]);
						site[1].addNeighbor(site[2]);
					}
				}
			}
		}
		
		HashSet<Pnt> done = new HashSet<Pnt>(initialTriangle);
		for (Triangle triangle : dt) {
			double randomY = 0;//R.nextDouble() * 100;
			for (Pnt point : triangle) {
				if (done.contains(point)) {
					continue;
				} else {
					Region newRegion = new Region();
					Site site = sites[point.iIndex][point.jIndex];
					newRegion.setSite(site);
					
					done.add(point);
					List<Triangle> list = dt.surroundingTriangles(point, triangle);
					Pnt[] vertices = new Pnt[list.size()];
					int i = 0;
					
					for (Triangle tri : list) {
						vertices[i] = tri.getCircumcenter();
						Corner newCorner = new Corner(vertices[i].coord(0), randomY, vertices[i].coord(1));
						newRegion.addCorner(newCorner);
						
						i++;
					}

					regions.add(newRegion);
				}
			}
		}
		return regions;
	}

}
